package com.itheima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hankcs.algorithm.AhoCorasickDoubleArrayTrie;
import com.itheima.admin.mapper.AdSensitiveMapper;
import com.itheima.admin.pojo.AdSensitive;
import com.itheima.admin.service.WemediaNewsAutoScanService;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.SensitiveWordUtil;
import com.itheima.common.util.ali.AliGreenScanner;
import com.itheima.common.vo.ResultVo;
import com.itheima.dfs.feign.DfsFeign;
import com.itheima.wemedia.dto.WmNewsContentNodeDto;
import com.itheima.wemedia.feign.WmNewsFeign;
import com.itheima.wemedia.pojo.WmNews;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import sun.rmi.runtime.Log;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {
    @Autowired
    private WmNewsFeign wmNewsFeign;

    @Autowired
    private AdSensitiveMapper adSensitiveMapper;

    @Autowired
    private AliGreenScanner aliGreenScanner;

    @Autowired
    private DfsFeign dfsFeign;

    /**
     * 文章自动审核
     *
     * @param wmNewsId
     * @param uuid
     */
    @Override
    public void autoScanWemediaNewsById(Long wmNewsId, String uuid) {
        //1. 通过文章id查询
        ResultVo<WmNews> resultVo = wmNewsFeign.getById(wmNewsId);
        log.info("远程调用自媒体查询文章信息: {}, success={}", uuid, resultVo.isSuccess());
        if (!resultVo.isSuccess()) {
            throw new LeadNewsException("远程调用自媒体查询文章信息失败");
        }
        WmNews wmNews = resultVo.getData();
        if (null == wmNews) {
            throw new LeadNewsException("远程调用自媒体查询文章信息失败,文章信息不存在");
        }
        //2. 判断文章状态 status=1才可以审核，否则不审核
        if (BusinessConstants.WmNewsConstants.STATUS_SUBMIT != wmNews.getStatus()) {
            throw new LeadNewsException("当前文章不是【待审核状态】！");
        }
        //3. 提取文本
        String text = getTextFromWmNews(wmNews);
        //4. 敏感词校验
        boolean flag = sensitiveWordsCheck(text);
        WmNews updatePojo = new WmNews();
        updatePojo.setId(wmNewsId);
        if (flag) {
            log.info("文章内容包含敏感词，审核失败!,{},{}", uuid, wmNewsId);
            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_FAIL);
            updatePojo.setReason("文章内容包含敏感词");
        } else {
            //没有检测到敏感词
            //5. 阿里的文本反垃圾
            try {
                Map<String, String> scanResult = aliGreenScanner.greenTextScan(text);
                if (null != scanResult && "pass".equals(scanResult.get("suggestion"))) {
                    // 文本审核通过
                    // 图片反垃圾
                    scanResult = imageCheck(wmNews);
                }
                //统一对垃圾结果处理
                if (null == scanResult) {
                    //阿里出问题了，需要人工处理
                    log.info("调用阿里文本反垃圾失败，需要人工审核, {},{}", uuid, wmNewsId);
                    updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL);
                    updatePojo.setReason("调用阿里文本反垃圾失败，需要人工审核");
                } else {
                    String suggestion = scanResult.get("suggestion");
                    switch (suggestion) {
                        case BusinessConstants.ScanConstants.PASS:
                            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_PASS);
                            break;
                        case BusinessConstants.ScanConstants.REVIEW:
                            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL);
                            break;
                        case BusinessConstants.ScanConstants.BLOCK:
                            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_FAIL);
                            updatePojo.setReason(scanResult.get("label"));
                            break;
                        default:
                            updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL);
                            break;
                    }
                }
            } catch (Exception e) {
                //e.printStackTrace();
                log.error("调用阿里文本反垃圾失败，需要人工审核, {},{}", uuid, wmNewsId, e);
                updatePojo.setStatus(BusinessConstants.WmNewsConstants.STATUS_MANUAL);
                updatePojo.setReason("调用阿里文本反垃圾失败，需要人工审核");
            }
        }
        // 更新文章状体
        ResultVo<WmNews> updateResult = wmNewsFeign.update(updatePojo);
        if (updateResult.isSuccess()) {
            log.info("文章自动审核结果更新成功：uuid={},id={},status={}", uuid, wmNewsId, updatePojo.getStatus());
        } else {
            log.info("文章自动审核结果更新失败：uuid={},id={},status={}", uuid, wmNewsId, updatePojo.getStatus());
        }
    }

    /**
     * 图片反垃圾处理
     * @param wmNews
     * @return
     */
    private Map<String, String> imageCheck(WmNews wmNews) throws Exception {
        //1. 提取文章中的图片
        // 内容 json [{type:text},{type:image}]
        String content = wmNews.getContent();
        if (StringUtils.isEmpty(content)){
            throw new LeadNewsException("文章内容不能为空!");
        }
        // 转成java对象，type=text不能要
        List<WmNewsContentNodeDto> contentList = JSON.parseArray(content, WmNewsContentNodeDto.class);
        // 提取到图片
        List<String> imageList = contentList.stream().filter(n -> "image".equals(n.getType())).map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());
        // 添加封面中的图片
        String images = wmNews.getImages();
        if (StringUtils.isNotEmpty(images)){
            //有封面
            String[] imageArr = images.split(",");
            imageList.addAll(Arrays.asList(imageArr));
        }
        // 图片去重
        imageList = imageList.stream().distinct().collect(Collectors.toList());

        //2. 远程调用dfs下载图片，得到图片字节流集合
        if (!CollectionUtils.isEmpty(imageList)){
            ResultVo<List<byte[]>> downloadResult = dfsFeign.download(imageList);
            if (!downloadResult.isSuccess()){
                throw new LeadNewsException("下载图片失败!");
            }
            List<byte[]> imageDataList = downloadResult.getData();
            //3. 调用ali图片反垃圾
            Map<String, String> result = aliGreenScanner.imageScan(imageDataList);
            //4. 返回结果
            return result;
        }
        // 没有图片，默认为成功
        return Collections.singletonMap("suggestion","pass");
    }

    /**
     * 敏感词校验
     * @param text
     * @return
     */
    /*private boolean sensitiveWordsCheck(String text) {
        //1. 查询数据库中的所有敏感词
        List<AdSensitive> sensitiveList = adSensitiveMapper.selectList(new QueryWrapper<>());
        if (!CollectionUtils.isEmpty(sensitiveList)){
            List<String> sensitiveWordsList = sensitiveList.stream().map(AdSensitive::getSensitives)
                    .filter(s -> "".equals(s.trim())).collect(Collectors.toList());
            //2. 调用工具类，初始化
            SensitiveWordUtil.initMap(sensitiveWordsList);
            //3. 检测文件
            Map<String, Integer> stringIntegerMap = SensitiveWordUtil.matchWords(text);
            //4. 返回结果
            return stringIntegerMap.size()>0;
        }
        return false;
    }*/

    /**
     * 使用 双数组字典
     * @param text
     * @return
     */
    private boolean sensitiveWordsCheck(String text) {
        //1. 查询数据库中的所有敏感词
        List<AdSensitive> sensitiveList = adSensitiveMapper.selectList(new QueryWrapper<>());
        if(!CollectionUtils.isEmpty(sensitiveList)){
            Map<String, String> map = sensitiveList.stream().map(AdSensitive::getSensitives)
                    .filter(s -> "".equals(s.trim())).collect(Collectors.toMap(Function.identity(), Function.identity()));
            //2. 调用工具类，初始化
            AhoCorasickDoubleArrayTrie<String> acdat = new AhoCorasickDoubleArrayTrie<String>();

            acdat.build(map);
            // Test it
            List<AhoCorasickDoubleArrayTrie.Hit<String>> wordList = acdat.parseText(text);
            return wordList.size()>0;
        }
        return false;
    }

    public static void main(String[] args) {
        TreeMap<String, String> map = new TreeMap<String, String>();
        String[] keyArray = new String[]
                {
                        "hers",
                        "his",
                        "she",
                        "he"
                };
        for (String key : keyArray)
        {
            map.put(key, key);
        }
        // Build an AhoCorasickDoubleArrayTrie
        AhoCorasickDoubleArrayTrie<String> acdat = new AhoCorasickDoubleArrayTrie<String>();
        acdat.build(map);
        // Test it
        final String text = "uhers";
        List<AhoCorasickDoubleArrayTrie.Hit<String>> wordList = acdat.parseText(text);
        wordList.forEach(System.out::println);
    }

    /**
     * 提取文章中的文本内容
     * @param wmNews
     * @return
     */
    private String getTextFromWmNews(WmNews wmNews) {
        // 内容 json [{type:text},{type:image}]
        String content = wmNews.getContent();
        if (StringUtils.isEmpty(content)){
            throw new LeadNewsException("文章内容不能为空!");
        }
        // 转成java对象，type=image不能要
        List<WmNewsContentNodeDto> contentList = JSON.parseArray(content, WmNewsContentNodeDto.class);
        // 只能提取type = text
        List<String> textContentList = contentList.stream().filter(n -> "text".equals(n.getType())).map(WmNewsContentNodeDto::getValue).collect(Collectors.toList());
        //标题
        textContentList.add(wmNews.getTitle());
        return String.join(",", textContentList);
    }
}
